package com.hmsm.dingtalk.openapi.auth;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Formatter;
import java.util.Timer;

import javax.servlet.http.HttpServletRequest;

import com.alibaba.fastjson.JSONObject;
import com.dingtalk.open.client.api.model.corp.JsapiTicket;
import com.dingtalk.open.client.api.service.corp.CorpConnectionService;
import com.dingtalk.open.client.api.service.corp.JsapiService;
import com.dingtalk.open.client.api.service.corp.SnsService;
import com.hmsm.dingtalk.HmsmCorpConnectionService;
import com.hmsm.dingtalk.HmsmJsapiService;
import com.hmsm.dingtalk.HmsmSnsService;
import com.hmsm.dingtalk.openapi.AppConfig;
import com.hmsm.dingtalk.openapi.EnterpriseConfig;
import com.hmsm.dingtalk.openapi.OApiException;
import com.hmsm.dingtalk.openapi.OApiResultException;
import com.hmsm.dingtalk.openapi.utils.FileUtils;
import com.hmsm.dingtalk.openapi.utils.HttpHelper;

public class AuthHelper {

	// public static String jsapiTicket = null;
	// public static String accessToken = null;
	public static Timer timer = null;
	// 调整到1小时50分钟
	public static final long cacheTime = 1000 * 60 * 55 * 2;
	public static long currentTime = 0 + cacheTime + 1;
	public static long lastTime = 0;
	public static SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	/*
	 * 在此方法中，为了避免频繁获取access_token，
	 * 在距离上一次获取access_token时间在两个小时之内的情况，
	 * 将直接从持久化存储中读取access_token
	 * 
	 * 因为access_token和jsapi_ticket的过期时间都是7200秒
	 * 所以在获取access_token的同时也去获取了jsapi_ticket
	 * 注：jsapi_ticket是在前端页面JSAPI做权限验证配置的时候需要使用的
	 * 具体信息请查看开发者文档--权限验证配置
	 */
	public static String getAccessToken(EnterpriseConfig enterpriseConfig) throws OApiException {
		String accToken = enterpriseConfig.getAccessTokenValue();
		
		if (accToken==null){
			long curTime = System.currentTimeMillis();
			JSONObject accessTokenValue = (JSONObject) FileUtils.getValue("accesstoken", enterpriseConfig.CORP_ID);
			String jsTicket = "";
			long expireTime;
			JSONObject jsontemp = new JSONObject();
			if (accessTokenValue == null || curTime  >= accessTokenValue.getLong("begin_time") + cacheTime) {
		        CorpConnectionService corpConnectionService = new HmsmCorpConnectionService();
				try {
			        accToken = corpConnectionService.getCorpToken(enterpriseConfig.CORP_ID, enterpriseConfig.CORP_SECRET);
			        expireTime = curTime + cacheTime;
			        // save accessToken
					JSONObject jsonAccess = new JSONObject();
					jsontemp.clear();
					jsontemp.put("access_token", accToken);
					jsontemp.put("begin_time", curTime);
					jsonAccess.put(enterpriseConfig.CORP_ID, jsontemp);
					FileUtils.write2File(jsonAccess, "accesstoken");
					
				} catch (Exception e) {
					e.printStackTrace();
					expireTime = curTime;
				}

			} else {
				accToken = accessTokenValue.getString("access_token");
				expireTime = accessTokenValue.getLong("begin_time") + cacheTime;
			}
			enterpriseConfig.setAccessToken(accToken, expireTime);
		}

		return accToken;
	}

	/*
	 * 在此方法中，为了避免频繁获取access_token，
	 * 在距离上一次获取access_token时间在两个小时之内的情况，
	 * 将直接从持久化存储中读取access_token
	 * 
	 * 因为access_token和jsapi_ticket的过期时间都是7200秒
	 * 所以在获取access_token的同时也去获取了jsapi_ticket
	 * 注：jsapi_ticket是在前端页面JSAPI做权限验证配置的时候需要使用的
	 * 具体信息请查看开发者文档--权限验证配置
	 */
	public static String getAppToken(AppConfig appConfig) throws OApiException {
		String appToken = appConfig.getAppTokenValue();
		
		if (appToken==null){
			long curTime = System.currentTimeMillis();
			JSONObject appTokenValue = (JSONObject) FileUtils.getValue("app_token", appConfig.getAppId());
			long expireTime;
			JSONObject jsontemp = new JSONObject();
			if (appTokenValue == null || curTime  >= appTokenValue.getLong("begin_time") + cacheTime) {
		        SnsService snsService = new HmsmSnsService();
				// sdk似乎有问题
				try {
			        appToken = snsService.getToken(appConfig.getAppId(), appConfig.getAppSecret());
			        expireTime = curTime + cacheTime;
			        // save accessToken
					JSONObject jsonAccess = new JSONObject();
					jsontemp.clear();
					jsontemp.put("app_token", appToken);
					jsontemp.put("begin_time", curTime);
					jsonAccess.put(appConfig.getAppId(), jsontemp);
					FileUtils.write2File(jsonAccess, "app_token");
					
				} catch (Exception e) {
					e.printStackTrace();
					expireTime = curTime;
				}

			} else {
				appToken = appTokenValue.getString("app_token");
				expireTime = appTokenValue.getLong("begin_time") + cacheTime;
			}
			appConfig.setAppToken(appToken, expireTime);
		}

		return appToken;
	}

	// 正常的情况下，jsapi_ticket的有效期为7200秒，所以开发者需要在某个地方设计一个定时器，定期去更新jsapi_ticket
	public static String getJsapiTicket(String accessToken, EnterpriseConfig enterpriseConfig) throws OApiException {
		String jsTicket = "";

		JSONObject jsTicketValue = (JSONObject) FileUtils.getValue("jsticket", enterpriseConfig.CORP_ID);
		long curTime = System.currentTimeMillis();

		 if (jsTicketValue == null || curTime -
		 jsTicketValue.getLong("begin_time") >= cacheTime) {
			try {
				JsapiService jsapiService = new HmsmJsapiService();

				JsapiTicket JsapiTicket = jsapiService.getJsapiTicket(accessToken, "jsapi");
				jsTicket = JsapiTicket.getTicket();

				JSONObject jsonTicket = new JSONObject();
				JSONObject jsontemp = new JSONObject();
				jsontemp.clear();
				jsontemp.put("ticket", jsTicket);
				jsontemp.put("begin_time", curTime);
				jsonTicket.put(enterpriseConfig.CORP_ID, jsontemp);
				FileUtils.write2File(jsonTicket, "jsticket");
			} catch (Exception e) {
				e.printStackTrace();
			}
		 } else {
			 jsTicket = jsTicketValue.getString("ticket");
		 }
		return jsTicket;
	}

	public static String sign(String ticket, String nonceStr, long timeStamp, String url) throws OApiException {
		String plain = "jsapi_ticket=" + ticket + "&noncestr=" + nonceStr + "&timestamp=" + String.valueOf(timeStamp)
				+ "&url=" + url;
		try {
			MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
			sha1.reset();
			sha1.update(plain.getBytes("UTF-8"));
			return bytesToHex(sha1.digest());
		} catch (NoSuchAlgorithmException e) {
			throw new OApiResultException(e.getMessage());
		} catch (UnsupportedEncodingException e) {
			throw new OApiResultException(e.getMessage());
		}
	}

	private static String bytesToHex(byte[] hash) {
		Formatter formatter = new Formatter();
		for (byte b : hash) {
			formatter.format("%02x", b);
		}
		String result = formatter.toString();
		formatter.close();
		return result;
	}

	@SuppressWarnings("deprecation")
	public static String getConfig(HttpServletRequest request, EnterpriseConfig enterpriseConfig) {
		String urlString = request.getRequestURL().toString();
		String queryString = request.getQueryString();

		String queryStringEncode = null;
		String url;
		if (queryString != null) {
			try {
				queryStringEncode = URLDecoder.decode(queryString, "UTF-8");
			} catch (UnsupportedEncodingException e) {
				queryStringEncode = URLDecoder.decode(queryString);
			}
			url = urlString + "?" + queryStringEncode;
		} else {
			url = urlString;
		}
		
		String nonceStr = "abcdefg";
		long timeStamp = System.currentTimeMillis() / 1000;
		String signedUrl = url;
		String accessToken = null;
		String ticket = null;
		String signature = null;
		String agentid = null;

		try {
			accessToken = AuthHelper.getAccessToken(enterpriseConfig);
	       
			ticket = AuthHelper.getJsapiTicket(accessToken, enterpriseConfig);
			signature = AuthHelper.sign(ticket, nonceStr, timeStamp, signedUrl);
			agentid = "";
			
		} catch (OApiException  e) {
			e.printStackTrace();
		}
		String configValue = "{jsticket:'" + ticket + "',signature:'" + signature + "',nonceStr:'" + nonceStr + "',timeStamp:'"
		+ timeStamp + "',corpId:'" + enterpriseConfig.CORP_ID + "',agentid:'" + agentid+  "'}";
		System.out.println(configValue);
		return configValue;
	}


	public static String getSsoToken(EnterpriseConfig enterpriseConfig) throws OApiException {
		String url = "https://oapi.dingtalk.com/sso/gettoken?corpid=" + enterpriseConfig.CORP_ID + "&corpsecret=" + enterpriseConfig.SSO_Secret;
		JSONObject response = HttpHelper.httpGet(url);
		String ssoToken;
		if (response.containsKey("access_token")) {
			ssoToken = response.getString("access_token");
		} else {
			throw new OApiResultException("Sso_token");
		}
		return ssoToken;

	}

}
